﻿
Imports System.Reflection
Imports std
Imports centrosphere
Imports centrosphere.job
Imports command = centrosphere.job.storage.command
Imports jobworker_lock_t = lockWrapper(Of locks.monitorlock)

Partial Public Class storageJobConsumer
    Inherits jobConsumer(Of storageJob)

    Private Delegate Function jobworker(ByVal s As islice,
                                        ByVal j As storageJob,
                                        ByVal l As jobworker_lock_t) As eventComb
    Private Delegate Function jobinitializer(ByVal j As storageJob) As Boolean
    Private Shared ReadOnly initials As vector(Of String) = Nothing
    Private Shared ReadOnly works As vector(Of String) = Nothing
    Private workers As invokers(Of jobworker) = Nothing
    Private initializers As invokers(Of jobinitializer) = Nothing
    Private Const locked As Int32 = 1
    Private Const unlocked As Int32 = 0
    Private writelocked As Int32 = unlocked
    Private readlocked As Int32 = unlocked

    Shared Sub New()
        works = New vector(Of String)()
        initials = New vector(Of String)()
        job.storage.traversal(Sub(ByRef s As String, ByRef i As command, ByRef j As Int64)
                                  works.push_back(s)
                                  initials.push_back(strcat("init_", s))
                              End Sub)
    End Sub

    Public Sub New()
        initializers = New invokers(Of jobinitializer)(
                                BindingFlags.Static Or BindingFlags.NonPublic Or BindingFlags.Instance,
                                Me,
                                +initials)
        workers = New invokers(Of jobworker)(BindingFlags.Static Or BindingFlags.NonPublic,
                                             Me,
                                             +works)
        ReDim command_required(job.storage.count - 1)
        initial_command_required()
    End Sub

    Private slices() As islice = Nothing

    Private Shared Shadows Function initial(ByVal name As String,
                                            ByVal config As configParser,
                                            ByVal c As storageJobConsumer) As Boolean
        assert(Not config Is Nothing)
        assert(Not c Is Nothing)
        Dim sliceCount As Int64 = 0
        sliceCount = config.parameter(name, "sliceCount", 64)
        ReDim c.slices(sliceCount - 1)
        Dim sliceType As String = Nothing
        sliceType = config.parameter(name, "sliceType", "mapslice")
        For i As Int64 = 0 To sliceCount - 1
            Dim s As islice = Nothing
            Dim obj As Object = Nothing
            If configLoader.generateComponent(name, sliceType, obj) AndAlso
               convertor.cast(Of islice)(obj, s) Then
                c.slices(i) = wrapperManager.wrap(s, config, name)
            Else
                raiseError(errorHandle.errorType.user,
                           "cannot generate component ", sliceType, " or the component is not an islice")
                Return False
            End If
        Next

        Return consumer.initial(name, config, c)
    End Function

    Public Shared Shadows Function initial(ByRef name As String,
                                           ByRef config As configParser,
                                           ByRef c As Object) As Boolean
        Return initial(name, config, convertor.cast(Of storageJobConsumer)(c))
    End Function

    Private Sub _lockread()
        atomic.eva(readlocked, locked)
    End Sub

    Private Sub _lockwrite()
        atomic.eva(writelocked, locked)
    End Sub

    Private Sub _unlockread()
        atomic.eva(readlocked, unlocked)
    End Sub

    Private Sub _unlockwrite()
        atomic.eva(writelocked, unlocked)
    End Sub

    Private Function init(ByVal c As Byte, ByVal j As storageJob) As Boolean
        Return ((Not initializers(c) Is Nothing AndAlso initializers(c)(j)) OrElse
                required_init(j)) AndAlso
               Not workers(c) Is Nothing
    End Function

    Protected NotOverridable Overrides Function workOn(ByVal j As storageJob,
                                                       Optional ByRef ec As eventComb = Nothing) As Boolean
        assert(Not j Is Nothing)
        If storage.valid(j.command) Then
            Dim offset As Byte = 0
            offset = j.command - job.firstOfStorage
            If init(offset, j) Then
                If slices.Length() = 1 Then
                    ec = workers(offset)(slices(0), j, Nothing)
                ElseIf storage.hashable(j.command) Then
                    Dim s As islice = Nothing
                    Dim index As Int32 = 0
                    index = hashcode2(j, slices.Length())
                    s = slices(index)
                    ec = workers(offset)(s, j, Nothing)
                Else
                    Dim ecs As vector(Of eventComb) = Nothing
                    ecs = New vector(Of eventComb)()
                    Dim l As jobworker_lock_t = Nothing
                    l = New jobworker_lock_t()
                    For i As Int64 = 0 To slices.Length() - 1
                        Dim wec As eventComb = Nothing
                        wec = workers(offset)(slices(i), j, l)
                        If Not wec Is Nothing Then
                            ecs.push_back(wec)
                        End If
                    Next

                    If ecs.size() > 0 Then
                        ec = New eventComb(Function() As Boolean
                                               Return waitfor(+ecs) AndAlso
                                                      goto_next()
                                           End Function,
                                           Function() As Boolean
                                               For i As Int64 = 0 To ecs.size() - 1
                                                   If Not ecs(i).end_result() Then
                                                       Return False
                                                   End If
                                               Next

                                               Return goto_end()
                                           End Function)
                    End If
                End If
            End If
            Return True
        Else
            raiseError(errorHandle.errorType.warning, "unknown command ", j.command, " got, ignore")
            Return False
        End If
    End Function

    Protected NotOverridable Overrides Sub [stop]()
        For i As Int64 = 0 To slices.Length() - 1
            slices(i).stop()
        Next
        MyBase.[stop]()
    End Sub
End Class
